package com.google.gautoard;

import static com.googlecode.objectify.ObjectifyService.ofy;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Handles the logging and storage for Arduinos/RPis
 * @author dras
 */
public class ServiceServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;
  private static final Logger log = Logger.getLogger(ServiceServlet.class.getName());

  /**
   * The main servlet handling code
   * @param req The HTTP Request
   * @param resp The HTTP Response
   * @throws IOException
   */
  public void processRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // part 1, check authorization
    String auth = req.getParameter("auth");

    if (!"test".equals(auth)) { // TODO(dras): put in proper authorization method
      // with hashkey
      resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized, please use your auth key");
      return;
    }

    log.info("1. authorization checked");

    // part 2, get any info from the client
    ArrayList<EventBean> events = arrangeRequest(req);
    log.log(Level.INFO, "2. received {0} entries from client", events.size());

    // and log any updated info (for long term logging)
    logEvents(events);
    log.log(Level.INFO, "3. updated info logged");

    // part 3, does the client want to set values?
    store(events);
    log.log(Level.INFO, "4. client values set");

    // part 4, did the client ask for any information?
    retrieve(events);
    for (EventBean event : events) {
      if (event.isAGet()) {
        resp.getWriter().write(event.toString());
      }
    }
    resp.getWriter().flush();
    log.log(Level.INFO, "5. client values got");
  }

  /**
   * Transforms the HTTP request into a list of EventBeans
   * @param req The HTTP Request
   * @return ArrayList of EventBeans
   * @throws IOException
   */
  public ArrayList<EventBean> arrangeRequest(HttpServletRequest req) throws IOException {
    log.log(Level.INFO, "Starting arrangeRequest");
    ArrayList<EventBean> veb = new ArrayList<>();
    String keyprefix = "";

    for (Enumeration<String> paramNames = req.getParameterNames(); paramNames.hasMoreElements();) {
      String name = paramNames.nextElement();
      log.log(Level.INFO, "got a name:{0}", name);

      if ("auth".equals(name)) {
        continue; // the auth isn't a bean
      }

      if ("keyprefix".equals(name)) {
        log.log(Level.INFO, "set prefix:{0}", name);
        keyprefix = req.getParameter("keyprefix");
        continue;
      }

      String[] pValues = req.getParameterValues(name);
      log.log(Level.INFO, "found {0} values", pValues.length);

      if (pValues.length == 1) {
        String pValue = pValues[0];
        log.log(Level.INFO, "pValue={0}", pValue);

        if (pValue.length() == 0) {
          // name with no value, they must want the value
          EventBean eb = new EventBean(keyprefix + name);
          veb.add(eb);
          log.log(Level.INFO, "arrange get:{0}", eb);
        } else {
          EventBean eb = new EventBean(keyprefix + name + "=" + pValue);
          veb.add(eb);
          log.log(Level.INFO, "arranged set:{0}", eb);
        }
      } // else multiple values for this key...not used by this app
    }
    return veb;
  }

  /**
   * Writes the EventBean to the log
   * @param beans to write
   */
  public void logEvents(ArrayList<EventBean> beans) {
    for (EventBean bean : beans) {
      if (bean.isUpdate()) {
        bean.log();
      }
    }
  }

  /**
   * Stores the EventBean in the store
   * @param beans to store
   */
  public void store(ArrayList<EventBean> beans) {
    for (EventBean bean : beans) {
      if (bean.isASet()) {
        log.log(Level.INFO, "Saving: {0}", bean);
        bean.store();
      }
    }
  }

  /**
   * Gets the EventBean from the store
   * @param beans to retrieve
   */
  public void retrieve(ArrayList<EventBean> beans) {
    for (EventBean bean : beans) {
      if (bean.isAGet()) {
        log.log(Level.INFO, "Retrieving: {0}", bean);
        bean.load();
      }
    }
  }

  /**
   * Handles the HTTP <code>GET</code> method.
   *
   * @param request servlet request
   * @param response servlet response
   * @throws ServletException if a servlet-specific error occurs
   * @throws IOException if an I/O error occurs
   */
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  /**
   * Handles the HTTP <code>POST</code> method.
   *
   * @param request servlet request
   * @param response servlet response
   * @throws ServletException if a servlet-specific error occurs
   * @throws IOException if an I/O error occurs
   */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }
}
